from flask import Flask, render_template, request, jsonify, session
import config
from exts import db, fetch_data, fetch_week, time_desc, session_name, sesison_pwd, group_names
from models import OfficeModel, OrderModel
import time
import flask_whooshalchemyplus
from mails import sendMail
from threading import Thread

app = Flask(__name__)
app.config.from_object(config)
db.init_app(app)
flask_whooshalchemyplus.init_app(app)

app.jinja_env.variable_start_string = '{{ '
app.jinja_env.variable_end_string = ' }}'


with app.app_context():
    db.create_all()


@app.route('/')
def hello_world():

    weeks = fetch_week()
    # 办公室信息
    get_office = request.args.get('office')
    office = OfficeModel.query.filter(get_office == OfficeModel.name).first()

    all_offices = OfficeModel.query.all()
    offices = [{'name': x.desc} for x in all_offices]
    if office:
        office_desc = office.desc
    else:
        office_desc = '五味子'

    # 允许的点击位置
    results = fetch_data()

    groups = [{'name': x} for x in group_names()]

    return render_template('date_picker.html', time_span=results, weeks=weeks, offices=offices, select_office=office_desc, groups=groups)


@app.route('/canSelect/')
def can_select():
    start = int(request.args.get('start'))
    end = int(request.args.get('end'))
    week = int(request.args.get('week'))
    office = request.args.get('office')

    ordered = ordered_time(office, week)

    new_orders = []
    for aOrder in ordered:
        new_orders.extend(list(range(aOrder.order_from, aOrder.order_to + 1)))

    select_range = set(range(start, end))

    inter = select_range.intersection(set(new_orders))

    if len(inter) > 0:
        return jsonify({'errorTip': '所选区间已被预订', 'status': 400})
    else:
        return jsonify({'data': None, 'status': 200})


@app.route('/search/')
def search():
    search_text = request.args.get('query')
    orderes = OrderModel.query.whoosh_search(search_text).all()
    ordered = groupOrder(order_convert(orderes))
    return render_template('order_list.html', ordered=ordered, title=search_text)


@app.route('/orderlist/')
def order_list():
    orderes = OrderModel.query.order_by('-create_time').all()
    ordered = groupOrder(order_convert(orderes))
    return render_template('order_list.html', ordered=ordered, title="预订记录")


def groupOrder(ordered):
    # 分组
    now_time = int(time.time())

    res = {}
    for aOrder in ordered:
        a_from = (aOrder['order_from'] - 7) * 1800 + 25200 + aOrder['order_day'] - 8 * 3600
        a_to = (aOrder['order_to'] - 7) * 1800 + 25200 + aOrder['order_day'] - 8 * 3600
        if (a_from <= now_time) & (a_to >= now_time):
            if not res.get('now'):
                res['now'] = []
            res['now'].append(aOrder)
        elif a_from >= now_time:
            if not res.get('future'):
                res['future'] = []
            res['future'].append(aOrder)
        elif a_to <= now_time:
            if not res.get('past'):
                res['past'] = []
            res['past'].append(aOrder)

    return res


def order_convert(orders):
    ordered = []
    for order in orders:
        ord_convert = order.to_dict()
        ord_convert['time_desc'] = time_desc(order.order_from, order.order_to + 1, order.order_day)
        ordered.append(ord_convert)
    return ordered


# 获取已被选择的内容
@app.route('/getOrdered/')
def get_ordered():
    office = request.args.get('office')
    week = request.args.get('week')
    ordered = ordered_time(office, int(week))
    allows = int((time.time() - 25200 - time_offset(0) + 8 * 3600) / 1800)

    order_json = jsonify({'data': {'order': [x.to_dict() for x in ordered], 'allow': allows}})
    return order_json


def runMail(**kwargs):
    order = kwargs['order']
    ord_convert = order.to_dict()
    ord_convert['time_desc'] = time_desc(order.order_from, order.order_to + 1, order.order_day)
    sendMail(ord_convert)


@app.route('/submit/')
def submit():
    user_name = request.args.get('user_name')
    user_depart = request.args.get('user_depart')
    reason = request.args.get('reason')
    start_hour = request.args.get('start_hour')
    end_hour = request.args.get('end_hour')
    select_week = request.args.get('select_week', '0')

    office = request.args.get('office', '').strip()

    office_model = OfficeModel.query.filter(OfficeModel.desc == office).first()
    if not office_model:
        return jsonify({'errorTip': '未能查到办公室' + '"' + office + '"', 'status': 500})

    startInterval = (int(start_hour) - 7) * 1800 + 25200 + time_offset(select_week) - 8 * 3600
    if startInterval <= time.time():
        return jsonify({'errorTip': '不能选择过去的时间', 'status': 500})

    new_order = OrderModel(user_name=user_name,depart_name=user_depart,reason=reason,order_from=start_hour, order_to=end_hour, office_id=office_model.id)
    new_order.order_day = time_offset(select_week)
    db.session.add(new_order)
    db.session.commit()

    Thread(target=runMail, kwargs={'order': new_order}).start()

    flask_whooshalchemyplus.index_one_model(OrderModel)
    return jsonify({'data': None, 'status': 200})


# 管理页面
@app.route('/manage/')
def manage():
    return render_template('manage.html')


@app.route('/officeManage/')
def office_manage():
    offices = OfficeModel.query.all()

    off = [x.to_dict() for x in offices]
    return render_template('office_manage.html', offices=off)


@app.route('/orderManage/')
def order_manage():
    orderes = OrderModel.query.order_by('-create_time').all()
    ordered = order_convert(orderes)
    return render_template('order_manage.html', ordered=ordered)


@app.route('/about/')
def about():
    return render_template('about.html')


@app.route('/addOffice/')
def add_office():
    name = request.args.get('name')
    desc = request.args.get('desc')

    same_names = OfficeModel.query.filter(OfficeModel.name == name).all()
    if same_names:
        return jsonify({'errorTip': '存在同名name:{},放弃添加'.format(name), 'status': 500})

    same_descs = OfficeModel.query.filter(OfficeModel.desc == desc).all()
    if same_descs:
        return jsonify({'errorTip': '存在同名desc:{},放弃添加'.format(name), 'status': 500})

    office1 = OfficeModel(name=name, desc=desc)
    db.session.add(office1)
    db.session.commit()
    return jsonify({'data': None, 'status': 200})


@app.route('/removeOrder/')
def remove_order():
    aId = request.args.get('id')
    if not aId:
        return jsonify({'errorTip': '参数错误，缺少参数"id"', 'status': 500})
    order = OrderModel.query.filter(OrderModel.id == int(aId)).all()
    if not order:
        return jsonify({'errorTip': '未能查询到id={}的订单信息'.format(aId), 'status': 500})

    db.session.delete(order[0])
    db.session.commit()
    flask_whooshalchemyplus.index_one_model(OrderModel)
    return jsonify({'data': None, 'status': 200})


@app.route('/removeOffice/')
def remove_office():
    allOffices = OfficeModel.query.all()
    if len(allOffices) <= 1:
        return jsonify({'errorTip': '只剩下一个办公室，无法删除', 'status': 500})
    aId = request.args.get('id')
    if not aId:
        return jsonify({'errorTip': '参数错误，缺少参数"id"', 'status': 500})
    office = OfficeModel.query.filter(OfficeModel.id == int(aId)).all()
    if not office:
        return jsonify({'errorTip': '未能查询到id={}的办公室信息'.format(aId), 'status': 500})

    db.session.delete(office[0])
    db.session.commit()
    return jsonify({'data': None, 'status': 200})


@app.route('/loginValidate/')
def login_validate():
    user = session.get('user_name')
    if not user:
        return jsonify({'errorTip': '未查询到session', 'status': 500})

    if user == session_name:
        return jsonify({'data': None, 'status': 200})
    return jsonify({'errorTip': 'session故障', 'status': 500})


@app.route('/pwdValidate/')
def pwd_validate():
    username = request.args.get('username')
    pwd = request.args.get('password')
    if (username == session_name) & (pwd == sesison_pwd):
        save_session(username)
        return jsonify({'data': None, 'status': 200})
    return jsonify({'errorTip': '用户名或密码错误', 'status': 500})


# 获取偏移后的时间戳
def time_offset(select):
    cur_time = time.time()
    return cur_time - cur_time % 86400 + 86400 * float(select)


# 获取某一天的时间戳差
def time_duration(offset):
    cur_time = time.time()
    start = cur_time - cur_time % 86400 + 86400 * offset - 8 * 3600
    return [start, start + 86400]


# 获取某天的预订信息
def ordered_time(office, week):

    office_model = OfficeModel.query.filter(OfficeModel.desc == office.strip()).first()
    if not office_model:
        return []

    duration = time_duration(int(week))
    ordered = OrderModel.query.filter((OrderModel.office_id == office_model.id) & (OrderModel.order_day > duration[0]) & (OrderModel.order_day <= duration[1])).all()
    return ordered


def save_session(user_name):
    session['user_name'] = user_name


# API **********************
@app.route('/api/orderList/')
def get_order_list():
    orderes = OrderModel.query.all()
    ordered = groupOrder(order_convert(orderes))
    return jsonify({'data': ordered, 'status':200})


@app.route('/api/order/', methods=['POST'])
def api_order():
    user_name = request.form.get('user_name')
    user_depart = request.form.get('user_depart')
    reason = request.form.get('reason')
    start_hour = request.form.get('start_hour')
    end_hour = request.form.get('end_hour')
    select_week = request.form.get('select_week', '0')

    office = request.form.get('office', '').strip()
    office_model = OfficeModel.query.filter(OfficeModel.desc == office).first()
    if not office_model:
        return jsonify({'errorTip': '未能查到办公室' + '"' + office + '"', 'status': 400})

    startInterval = (int(start_hour) - 7) * 1800 + 25200 + time_offset(select_week) - 8 * 3600
    if startInterval <= time.time():
        return jsonify({'errorTip': '不能选择过去的时间', 'status': 500})

    new_order = OrderModel(user_name=user_name,depart_name=user_depart,reason=reason,order_from=start_hour, order_to=end_hour, office_id=office_model.id)
    new_order.order_day = time_offset(select_week)
    db.session.add(new_order)
    db.session.commit()

    flask_whooshalchemyplus.index_one_model(OrderModel)
    return jsonify({'data': None, 'status': 200})


@app.route('/api/search')
def api_search():
    search_text = request.args.get('query')
    orderes = OrderModel.query.whoosh_search(search_text).all()
    ordered = groupOrder(order_convert(orderes))
    return jsonify({'data': ordered, 'status': 200})


@app.route('/api/addOffice', methods=['POST'])
def api_add_office():
    name = request.form.get('name')
    desc = request.form.get('desc')

    same_names = OfficeModel.query.filter(OfficeModel.name == name).all()
    if same_names:
        return jsonify({'errorTip': '存在同名name:{},放弃添加'.format(name), 'status': 400})

    same_descs = OfficeModel.query.filter(OfficeModel.desc == desc).all()
    if same_descs:
        return jsonify({'errorTip': '存在同名desc:{},放弃添加'.format(name), 'status': 400})

    office1 = OfficeModel(name=name, desc=desc)
    db.session.add(office1)
    db.session.commit()
    return jsonify({'data': None, 'status': 200})


@app.route('/api/dropOffice', methods=['POST'])
def api_drop_office():
    desc = request.form.get('desc')
    same_names = OfficeModel.query.filter(OfficeModel.desc == desc).all()
    if not same_names:
        return jsonify({'errorTip': '输入的desc:{}不存在'.format(desc), 'status': 400})

    db.session.delete(same_names[0])
    db.session.commit()

    flask_whooshalchemyplus.index_one_model(OrderModel)
    return jsonify({'data': None, 'status': 200})


@app.route('/api/dropOrder', methods=['POST'])
def api_drop_order():
    drop_id = request.form.get['order_id']
    drop_order = OrderModel.query.filter(OrderModel.id == drop_id).all()
    if not drop_order:
        return jsonify({'errorTip': '未能查找到对应订单', 'status': 400})
    db.session.delete(drop_order[0])
    db.session.commit()
    flask_whooshalchemyplus.index_one_model(OrderModel)
    return jsonify({'data': None, 'status': 200})


@app.route('/api/getOrder/')
def api_get_order():
    name = request.args.get('name')
    orders = OrderModel.query.filter(OrderModel.user_name == name).all()
    ordered = order_convert(orders)
    return jsonify({'data': ordered, 'status': 200})


if __name__ == '__main__':
    app.run()




